import relationSettings from './relationSettings.js'

import dictionary from '../bagua/dictionary.js'

import Judge from '@/utils/common/judge.js'

// 符号之间的关系
class Relation {
  constructor (objs = [], methods = [], keyObj = null) {
    this.init(objs, methods, keyObj)
  }
  
  /*
    objs 计算关系的对象分组
    methods 使用的方法列表
    keyObj 关键对象，若为null，执行方式为对象分组中的元素捉对厮杀，否则每一个都会和keyObj发生关系
  */
  init (objs = [], methods = [], keyObjs = null) {
    this.objs = objs
    this.keyObjs = keyObjs
    // 对方法进行分类
    this.sortMethods(methods)
    
    // 执行判断
    this.execute()
  }
  
  sortMethods (methods = []) {
    methods = methods.map(key => relationSettings[key])
    // 排列判断方法
    this.arrangeMethod = methods.filter(method => method && method.num === 2 && method.group === 'A')
    // 组合判断方法
    this.combineMethod = methods.filter(method => method && method.num === 2 && method.group === 'C')
    // 需要三个单元进行判断的方法
    this.tripleMethod = methods.filter(method => method && method.num === 3)
  }
  
  // 执行判断
  execute () {
    if (!this.keyObjs) {
      this.freeExecute()
    }
    else {
      this.keyExecute()
    }
  }
  
  // 对象分组内每一个都会和keyObj发生关系，这种情况无法进行三个单元的判断
  keyExecute () {
    // 初始化空的关系列表
    this.relations = []
    
    const len = this.objs.length
    const keyLen = this.keyObjs.length
    for (let i = 0; i < len; i++) {
      for (let j = 0; j < keyLen; j++) {
        // 执行排列算法
        this.arrangeMethod.forEach((method) => {
          // 因为是排列,所以下标调换还要进行一次判定
          this.doAction(method, [this.objs[i], this.keyObjs[j]])
          this.doAction(method, [this.keyObjs[j], this.objs[i]])
        })
        
        // 执行组合算法
        this.combineMethod.forEach((method) => {
          this.doAction(method, [this.objs[i], this.keyObjs[j]])
        })
        
        // 三元关系就无法执行
      }
    }
  }
  
  // 对象分组内的对象捉对厮杀
  freeExecute () {
    // 初始化空的关系列表
    this.relations = []
    
    const len = this.objs.length
    for (let i = 0; i < len; i++) {
      for (let j = i + 1; j < len; j++) {
        // 执行排列算法
        this.arrangeMethod.forEach((method) => {
          // 因为是排列,所以下标调换还要进行一次判定
          this.doAction(method, [this.objs[i], this.objs[j]])
          this.doAction(method, [this.objs[j], this.objs[i]])
        })
        
        // 执行组合算法
        this.combineMethod.forEach((method) => {
          this.doAction(method, [this.objs[i], this.objs[j]])
        })
        
        if (this.tripleMethod.length > 0) {
          for (let k = j + 1; k < len; k++) {
            // 执行三重单元算法
            this.tripleMethod.forEach((method) => {
              this.doAction(method, [this.objs[i], this.objs[j], this.objs[k]])
            })
          }          
        }
      }
    }
  }
  
  /*
    执行方法
    methodObj 方法对象
    arg2 对象集，代入方法的第一个参数
    args 代入方法的其他参数
  */
  doAction (methodObj) {
    if (typeof methodObj.method === 'function') {
      // 提取参数
      const args = Array.prototype.slice.call(arguments)
      
      // 如果指定了类别限制，需要做类别检查
      if (methodObj.types && Array.isArray(methodObj.types)) {
        const objs = args[1]
        const methodLen = methodObj.types.length
        const objLen = objs.length
        const len = objLen < methodLen ? objLen : methodLen
        for (let i = 0; i < len; i++) {
          // 多种合法类型用逗号分隔
          const typeList = methodObj.types[i].split('|')
          const typeListLen = typeList.length
          let isPass = false
          for (let j = 0; j < typeListLen; j++) {
            if (objs[i].types.indexOf(typeList[j]) >= 0) {
              isPass = isPass | true
            }            
          }
          
          if (!isPass) {
            // 类别一旦不符合，直接跳出函数，不执行
            return
          }
        }
      }
      
      const res = methodObj.method.apply(this, args.slice(1))
      // console.log(args[1][0].name, args[1][1].name, res)
      if (res) {
        // 追加类别标识
        res.type = methodObj.key
        // 追加检测文字,格式: 描述1|描述2|描述3...
        res.checkText = res.objs.map(obj => obj.description).join('|')
        this.relations.push(res)
      }
    }
  }
  
  // 删除一个单元，并去除所有有关的关系
  // isImme是否立即重新计算
  removeItem (desObj, isImme = true) {
    const index = this.objs.find(obj => obj.id === desObj.id)
    if (index < 0) {
      return
    }
    // 对象数组中删除目标
    this.objs.splice(index, 1)
    
    // 删除与目标相关的所有关系
    if (isImme) {
      this.relations = this.relations.filter((relation) => {
        const isExist = relation.objs.some(obj => obj.id === desObj.id)
        return !isExist
      })
    }
  }
  
  // 添加一个单元，并且计算该单元与其他所有单元的关系
  // isImme是否立即重新计算
  addItem (desObj, isImme = true) {
    this.objs.push(desObj)
    
    // 重新计算关系
    if (isImme) {
      this.execute()
    }
  }
  
  // 替换一个单元
  replaceItem (srcObj, desObj, isImme = true) {
    const index = this.objs.findIndex(obj => obj.id === srcObj.id)
    if (index < 0) {
      // 没找到源单位，直接添加新的单元
      this.addItem(desObj, isImme)
      return
    }
    // 替换
    this.objs.splice(index, 1, desObj)
    
    // 重新计算关系
    if (isImme) {
      this.execute()
    }
  }
  
  /* @section static */
  /* 
    判断对象组就某种规则产生关系
    返回结果，说明存在关系
    返回null，说明不存在关系
  */
  static checkRelation (key = 'tenGod') {
    const methodObj = relationSettings[key]
    if (!methodObj) {
      return null
    }
    
    if (typeof methodObj.method === 'function') {
      const args = Array.prototype.slice.call(arguments)
      const res = methodObj.method.apply(this, args.slice(1))
      if (res) {
        // 追加类别标识
        res.type = methodObj.key
        // 返回结果，说明存在关系
        return res
      }
    }
    
    return null
  }
  
  /* @section get */
  /*
    通过关键字筛选关系，建立筛选对象
    检查是否具有key关键字，若reverse为true，取反
  */
  findRelations (key = 'GAN', reverse = false) {
    if (typeof dictionary[key] === 'string') {
      this.relationsFinder = []
      this.relationsFinder.push({
        reverse,
        text: dictionary[key]
      })       
    }
    return this
  }
  
  // and过滤，检查是否具有key关键字，若reverse为true，取反
  findAnd (key = 'GAN', reverse = false) {
    if (typeof dictionary[key] === 'string' && Array.isArray(this.relationsFinder)) {
      this.relationsFinder.push({
        type: 'and',
        reverse,
        text: dictionary[key]
      })      
    }
    return this
  }
  
  // or过滤，检查是否具有key关键字，若reverse为true，取反
  findOr (key = 'GAN', reverse = false) {
    if (typeof dictionary[key] === 'string' && Array.isArray(this.relationsFinder)) {
      this.relationsFinder.push({
        type: 'or',
        reverse,
        text: dictionary[key]
      })      
    }
    return this
  }
  
  /*
    执行筛选
  */
  findExecute () {
    if (!Array.isArray(this.relationsFinder)) {
      return []
    }
    
    const relationsFinder = this.relationsFinder
    const len = relationsFinder.length
    delete this.relationsFinder
    
    return this.relations.filter((relation) => {
      // 确定接受检查部分
      const desText = relation.checkText
      
      // 检查函数
      const func = (text, keyText, isReverse) => {
        return () => {
          return isReverse ? text.indexOf(keyText) < 0 : text.indexOf(keyText) >= 0
        }
      }

      let checkObj = new Judge(func(desText, relationsFinder[0].text, relationsFinder[0].reverse))
      for (let i = 1; i < len; i++) {
        if (relationsFinder[i].type === 'and') {
          checkObj = checkObj.and(func(desText, relationsFinder[i].text, relationsFinder[i].reverse))
        }
        else {
          checkObj = checkObj.or(func(desText, relationsFinder[i].text, relationsFinder[i].reverse))
        }
      }
      
      return checkObj.end() === 1
    })
  }
}

export default Relation